#include <arpa/inet.h>
#include <cstring> 
#include <errno.h> 
#include <iostream>
#include <map>
#include <netdb.h> 
#include <netinet/in.h> 
#include <signal.h> 
#include <stdio.h>
#include <stdlib.h> 
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h> 
#include <unistd.h> 
#include <vector>

using namespace std;

#define PORT "1440" // the port client will be connecting to 
#define CHATPORT "1441"
#define MAXDATASIZE 100 // max number of bytes we can get at once 
#define MAXUSERNAMESIZE 15
/*
*	Global Variables
*/
int sockfd, otherclient; //server socket
char serveripaddress[INET_ADDRSTRLEN];

/*
*	Forward Declarations
*/
bool isOp(char* s);
void printhelp();
void connectServer(char *server, char *username);

/*
*	Function definitions
*/
bool isOp(char* s)
{
	if(strlen(s) >= 2 && s[0] == '/' )
	{
		if (strlen(s) >= 3 && s[2] !=' ')
			return false;
		
		if (s[1] == 'c' // connect
		||  s[1] == 'd' // disconnect
		||  s[1] == 'g' // getlist
		||  s[1] == 't' // talk
		||  s[1] == 'b' // bye
		||  s[1] == 'h' // help
		||  s[1] == 'q'	)// quit
			return true;
	}
	return false;
}

void printhelp()
{
	cout << "/c 				: (c)onnect to the server with a username\n";
	cout << "/d 				: (d)isconnect from server\n";
	cout << "/g 				: (g)et list of who is online\n";
	cout << "/t user			: (t)alk. Initiate chat with user\n";
	cout << "/b user			: (b)yebye. Close chat with user\n";
	cout << "/h 				: help\n";
	cout << "/q 				: quit\n";
	//also a hidden function /z to close server
}

void connectServer(string server, string username)
{
	//declare variables
	struct addrinfo hints, *servinfo, *p; 
	
	memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_STREAM; 
	int rv;
    if ((rv =  getaddrinfo(server.c_str(), PORT, &hints, &servinfo)) != 0) { 
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 
		exit(1);
    } 

    // loop through all the results and connect to the first we can 
    for(p = servinfo; p != NULL; p = p->ai_next) { 
        if ((sockfd = socket(p->ai_family, p->ai_socktype, 
                p->ai_protocol)) == -1) { 
            perror("client: socket"); 
            continue; 
        } 
        if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { 
            close(sockfd); 
            perror("client: connect"); 
            continue;
		} 
		break; 
	} 
	if (p == NULL) { 
		fprintf(stderr, "client: failed to connect\n"); 
		exit(1); 
	} 

	inet_ntop(p->ai_family, &(((struct sockaddr_in*)p->ai_addr)->sin_addr), 
		      serveripaddress, sizeof serveripaddress); 
 
	freeaddrinfo(servinfo); // all done with this structure
	if(send(sockfd, username.c_str(), strlen(username.c_str()), 0) == -1){
	  perror("username");
	  exit(1);
	}
	printf("client: connected to %s\n", serveripaddress);
}

int main(int argc, char *argv[]) 
{ 

	cout << "Welcome to Yink's chat client. type /h for help\n";
	//main running loop
	string  servername, username;
	username = "";
	int numbytes;
	char input[MAXDATASIZE];
	char buf[MAXDATASIZE];
	while (1)
	{	
		if (username.compare("") != 0)
		{
			cout << username << ": ";
		}
		cin.getline(input, MAXDATASIZE) ;
		if (isOp(input))
		{
			if (input[1] == 'h')
				printhelp();
			else if (input[1] == 'q')
			{
				if(send(sockfd, input, sizeof input, 0) == -1)
                    perror("/q send error");
                if((numbytes = recv(sockfd, buf, sizeof buf,0)) == -1)
                    perror("/q recv error");
                buf[numbytes] = '\0';
                cout << buf << endl;
				//close (sockfd);
				cout << "quitting\n";
				return 0;
			}
			else if (input[1] == 'c')
			{
				cout << "server ip address: ";
				cin >> servername;
				cout << "user name: ";
				cin >> username;
				while (username.length() >= 15)
				{
					cout << "Error: username too long\nuser name: ";
					cin >> username;
				}
				connectServer(servername, username);
			}
			else if (input[1] == 'd')
			{
				if(send(sockfd, input, sizeof input, 0) == -1)
                    perror("/d send error");
                if((numbytes = recv(sockfd, buf, sizeof buf,0)) == -1)
                    perror("/d recv error");
                buf[numbytes] = '\0';
                cout << buf << endl;
				//close (sockfd);
				username = "";
				cout << "disconnecting from: " << serveripaddress << endl;
			}
			else if (input[1] == 'g')
			{
				if(send(sockfd, input, sizeof input , 0) == -1)
				    perror("/g send error");
                if((numbytes = recv(sockfd, buf, sizeof buf, 0)) == -1)
                    perror("/g recv error");
				buf[numbytes] = '\0';
                cout << "Users online:" <<endl;
                cout << buf << endl;

			}
			else if (input[1] == 't')
			{
				if(send(sockfd, input, sizeof input , 0) == -1)
                    perror("/t send error");
				cout << "trying to talk to " << input << endl;
                if((numbytes = recv(sockfd, buf, sizeof buf, 0)) == -1)
                    perror("/t recv error");
				buf[numbytes] = '\0';
				if (strcmp (buf, "Error") == 0)
					cout << "Error, user not found\n";

				
			}
			else if (input[1] == 'b')
			{
				
			}

			
		}
		else
		{
			//not OP. do stuff. i.e. send msg to client

			// cout << "not quitting\n";
			// return 0;
		}
	}
	


	

	return 0; 
} 
